package com.smart.smartdata;

import android.util.Log;


import com.smart.smartdata.ble.IBeaconRecord;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.Formatter;


public class ByteUtil {
    /**
     * 用于建立十六进制字符的输出的小写字符数组
     */
    private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    /**
     * 用于建立十六进制字符的输出的大写字符数组
     */
    private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    public static byte[] getBytes(short data) {
        byte[] bytes = new byte[2];
        bytes[0] = (byte) (data & 0xff);
        bytes[1] = (byte) ((data & 0xff00) >> 8);
        return bytes;
    }

    public static byte[] getBytes(char data) {
        byte[] bytes = new byte[2];
        bytes[0] = (byte) (data);
        bytes[1] = (byte) (data >> 8);
        return bytes;
    }

    public static byte[] getBytes(int data) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) (data & 0xff);
        bytes[1] = (byte) ((data & 0xff00) >> 8);
        bytes[2] = (byte) ((data & 0xff0000) >> 16);
        bytes[3] = (byte) ((data & 0xff000000) >> 24);
        return bytes;
    }

    //大端(big endian):低地址存放高有效字节
    //小端(little endian):低字节存放低有效字节
    //AD值1	0x008----0x00A	3字节 (高字节在前)

    /**
     * 高字节在前，大端模式; int转Bytes数组
     *
     * @param value
     * @return
     */
    public static byte[] IntToByteArrayByBigEndia(int value) {
        byte[] src = new byte[4];
        src[0] = (byte) ((value >> 24) & 0xFF);
        src[1] = (byte) ((value >> 16) & 0xFF);
        src[2] = (byte) ((value >> 8) & 0xFF);
        src[3] = (byte) (value & 0xFF);
        return src;
    }

    /**
     * 大端模式，bytes转Int类型
     *
     * @param data
     * @return
     */
    public static int bytestoIntBigEndia(byte[] data) {
        if (data.length != 4) {
            return -1;
        }
        return (int) ((((data[0] & 0xff) << 24)
                | ((data[1] & 0xff) << 16)
                | ((data[2] & 0xff) << 8)
                | ((data[3] & 0xff) << 0)));
    }


    /**
     * int转Byte数组
     * 高字节在前，大端模式
     * 仅支持三个字节
     *
     * @param value
     * @return
     */
    public static byte[] IntToThreeBytesByBigEndia(int value) {
        byte[] src = new byte[3];
        src[0] = (byte) ((value >> 16) & 0xFF);
        src[1] = (byte) ((value >> 8) & 0xFF);
        src[2] = (byte) (value & 0xFF);
        return src;
    }


    /**
     * Byte数组转Int
     * 高字节在前，大端模式
     * 仅支持三个字节
     *
     * @param data
     * @return
     */
    public static int threeBytesToIntByBigEndia(byte[] data) {
        if (data.length != 3) {
            return -1;
        }
        return (int) ((((data[0] & 0xff) << 16)
                | ((data[1] & 0xff) << 8)
                | ((data[2] & 0xff) << 0)));
    }


    public static byte[] getBytes(long data) {
        byte[] bytes = new byte[8];
        bytes[0] = (byte) (data & 0xff);
        bytes[1] = (byte) ((data >> 8) & 0xff);
        bytes[2] = (byte) ((data >> 16) & 0xff);
        bytes[3] = (byte) ((data >> 24) & 0xff);
        bytes[4] = (byte) ((data >> 32) & 0xff);
        bytes[5] = (byte) ((data >> 40) & 0xff);
        bytes[6] = (byte) ((data >> 48) & 0xff);
        bytes[7] = (byte) ((data >> 56) & 0xff);
        return bytes;
    }

    public static byte[] getBytes(float data) {
        int intBits = Float.floatToIntBits(data);
        return getBytes(intBits);
    }

    public static byte[] getBytes(double data) {
        long intBits = Double.doubleToLongBits(data);
        return getBytes(intBits);
    }

    public static char[] getChars(byte[] bytes) {
        Charset cs = Charset.forName("UTF-8");
        ByteBuffer bb = ByteBuffer.allocate(bytes.length);
        bb.put(bytes).flip();
        CharBuffer cb = cs.decode(bb);
        return cb.array();
    }

    public static byte[] getBytes(String data, String charsetName) {
        Charset charset = Charset.forName(charsetName);
        return data.getBytes(charset);
    }

    public static short[] toShortArray(byte[] src) {
        int count = src.length >> 1;
        short[] dest = new short[count];
        for (int i = 0; i < count; i++) {
            dest[i] = (short) (src[i * 2] << 8 | src[2 * i + 1] & 0xff);
        }
        return dest;
    }

    public static byte[] getBytes(String data) {
        return getBytes(data, "GBK");
    }


    public static short getShort(byte[] bytes) {
        return (short) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
    }

    public static char getChar(byte[] bytes) {
        return (char) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
    }

    public static int getInt(byte[] bytes) {
        return (0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)) | (0xff0000 & (bytes[2] << 16)) | (0xff000000 & (bytes[3] << 24));
    }

    private static long get(int i) {
        switch (i) {
            case 0:
                return 0xff;
            case 1:
                return 0xff00;
            case 2:
                return 0xff0000;
            case 3:
                return 0xff000000;
            case 4:
                return 0xff00000000L;
            case 5:
                return 0xff0000000000L;
            case 6:
                return 0xff000000000000L;
        }
        return 0xff;
    }

    public static long getInt(byte[] bytes, int length) {
        long[] result = new long[length];
        for (int i = 0; i < bytes.length; i++) {
            result[i] = get(i) & bytes[i] << (8 * i);
        }
        long intR = result[0];
        for (int j = 1; j < result.length; j++) {
            intR = intR | result[j];
        }
        return intR;
    }

    public static long getLong(byte[] bytes) {
        return (0xffL & (long) bytes[0]) | (0xff00L & ((long) bytes[1] << 8)) | (0xff0000L & ((long) bytes[2] << 16)) | (0xff000000L & ((long) bytes[3] << 24))
                | (0xff00000000L & ((long) bytes[4] << 32)) | (0xff0000000000L & ((long) bytes[5] << 40)) | (0xff000000000000L & ((long) bytes[6] << 48)) | (0xff00000000000000L & ((long) bytes[7] << 56));
    }

    public static float getFloat(byte[] bytes) {
        return Float.intBitsToFloat(getInt(bytes));
    }

    public static double getDouble(byte[] bytes) {
        long l = getLong(bytes);
        System.out.println(l);
        return Double.longBitsToDouble(l);
    }

    public static String getString(byte[] bytes, String charsetName) {
        return new String(bytes, Charset.forName(charsetName));
    }

    public static String getString(byte[] bytes) {
        return getString(bytes, "GBK");
    }

    /**
     * 16进制表示的字符串转换为字节数组
     *
     * @param hexString 16进制表示的字符串
     * @return byte[] 字节数组
     */
    public static byte[] hexStringToByteArray(String hexString) {
        hexString = hexString.replaceAll(" ", "");
        int len = hexString.length();
        byte[] bytes = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            // 两位一组，表示一个字节,把这样表示的16进制字符串，还原成一个字节
            bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
                    .digit(hexString.charAt(i + 1), 16));
        }
        return bytes;
    }

    /**
     * 将字串传转换成GB2312编码格式Bytes
     *
     * @param string
     * @return
     */
    public static byte[] getBytesByGB2312(String string) {
        try {
            return string.getBytes("gb2312");
        } catch (Exception e) {
            return new byte[1];
        }
    }

    /**
     * 从指定位置的开始，取指定长度转HEX字串
     *
     * @param data
     * @param offset
     * @param length
     * @return
     */
    public static String encodeHexStr(byte[] data, int offset, int length) {
        byte[] newData = new byte[length];
        System.arraycopy(data, offset, newData, 0, length);
        return encodeHexStr(newData);
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param data byte[]
     * @return 十六进制String
     */
    public static String encodeHexStr(byte[] data) {
        return encodeHexStr(data, true);
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param data        byte[]
     * @param toLowerCase <code>true</code> 传换成小写格式 ， <code>false</code> 传换成大写格式
     * @return 十六进制String
     */
    public static String encodeHexStr(byte[] data, boolean toLowerCase) {
        return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param data     byte[]
     * @param toDigits 用于控制输出的char[]
     * @return 十六进制String
     */
    protected static String encodeHexStr(byte[] data, char[] toDigits) {
        return new String(encodeHex(data, toDigits));
    }

    /**
     * 将字节数组转换为十六进制字符数组
     *
     * @param data     byte[]
     * @param toDigits 用于控制输出的char[]
     * @return 十六进制char[]
     */
    protected static char[] encodeHex(byte[] data, char[] toDigits) {
        if (data == null)
            return null;
        int l = data.length;
        char[] out = new char[l << 1];
        for (int i = 0, j = 0; i < l; i++) {
            out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
            out[j++] = toDigits[0x0F & data[i]];
        }
        return out;
    }

    public static void main(String[] args) {

        byte[] data = getBytes(100);
    }

    /**
     * 解析蓝牙信息数据流
     *
     * @param scanData
     * @param record
     * @return
     */
    public static boolean fromScanData(byte[] scanData, IBeaconRecord record) {
        int startByte = 2;
        boolean patternFound = false;
        while (startByte <= 5) {
            if (((int) scanData[startByte + 2] & 0xff) == 0x02
                    && ((int) scanData[startByte + 3] & 0xff) == 0x15) {
                // yes! This is an iBeacon
                patternFound = true;
                break;
            } else if (((int) scanData[startByte] & 0xff) == 0x2d
                    && ((int) scanData[startByte + 1] & 0xff) == 0x24
                    && ((int) scanData[startByte + 2] & 0xff) == 0xbf
                    && ((int) scanData[startByte + 3] & 0xff) == 0x16) {

                return false;
            } else if (((int) scanData[startByte] & 0xff) == 0xad
                    && ((int) scanData[startByte + 1] & 0xff) == 0x77
                    && ((int) scanData[startByte + 2] & 0xff) == 0x00
                    && ((int) scanData[startByte + 3] & 0xff) == 0xc6) {

                return false;
            }
            startByte++;
        }

        if (patternFound == false) {
            // This is not an iBeacon

            return false;
        }

//        // 获得Major属性
//        record.major = (scanData[startByte + 20] & 0xff) * 0x100
//                + (scanData[startByte + 21] & 0xff);

        // 获得Minor属性

        record.minor = (scanData[startByte + 20] & 0xff) * 0x1000000
                + (scanData[startByte + 21] & 0x10000) + (scanData[startByte + 22] & 0xff) * 0x100 +
                +(scanData[startByte + 23] & 0xff);
        // record.tx_power = (int) scanData[startByte + 24]; // this one is
        // signed
        // record.accuracy = calculateAccuracy(record.tx_power, record.rssi);
        // if (record.accuracy < 0) {
        // return false;
        // }
        String s = bytesToHex(scanData).substring((startByte + 20) * 2, (startByte + 24) * 2);
        record.minor = ByteUtil.bytestoIntBigEndia(ByteUtil.hexStringToByteArray(s));
        Log.i("ByteUtil", bytesToHex(scanData) + " S:" + s + " minor:" + record.minor);
        try {

            byte[] proximityUuidBytes = new byte[16];
            System.arraycopy(scanData, startByte + 4, proximityUuidBytes, 0, 16);
            String hexString = bytesToHex(proximityUuidBytes);
            StringBuilder sb = new StringBuilder();
            sb.append(hexString.substring(0, 8));
            sb.append("-");
            sb.append(hexString.substring(8, 12));
            sb.append("-");
            sb.append(hexString.substring(12, 16));
            sb.append("-");
            sb.append(hexString.substring(16, 20));
            sb.append("-");
            sb.append(hexString.substring(20, 32));
            // beacon.put("proximity_uuid", sb.toString());
            // 获得UUID属性
            record.uuid = sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return true;
    }

    private static char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
            '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        int v;
        for (int j = 0; j < bytes.length; j++) {
            v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    public static String toHexString(byte[] input, String separator) {
        if (input==null) return null;

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < input.length; i++) {
            if (separator != null && sb.length() > 0) {
                sb.append(separator);
            }
            String str = Integer.toHexString(input[i] & 0xff);
            if (str.length() == 1) str = "0" + str;
            sb.append(str);
        }
        return sb.toString();
    }

    public static String toHexString(byte[] input) {
        return toHexString(input, " ");
    }

    public static byte[] fromInt32(int input){
        byte[] result=new byte[4];
        result[3]=(byte)(input >> 24 & 0xFF);
        result[2]=(byte)(input >> 16 & 0xFF);
        result[1]=(byte)(input >> 8 & 0xFF);
        result[0]=(byte)(input & 0xFF);
        return result;
    }

    public static byte[] fromInt16(int input){
        byte[] result=new byte[2];
        result[0]=(byte)(input >> 8 & 0xFF);
        result[1]=(byte)(input & 0xFF);
        return result;
    }

    public static byte[] fromInt16Reversal(int input){
        byte[] result=new byte[2];
        result[1]=(byte)(input>>8&0xFF);
        result[0]=(byte)(input&0xFF);
        return result;
    }

    public static String bytes2Hex(byte[] bytes) {
        Formatter formatter = new Formatter();
        for (byte b : bytes) {
            formatter.format("%02x ", b);
        }
        String hash = formatter.toString();
        formatter.close();
        return hash;
    }
}